feat(hub): whole-package zip download + file list on the agent page - #1843
Conversation
Before: the hub agent page showed only metadata — no way to grab the actual
package. After: a one-click 'Download .zip' (one archive with the client, docs,
and ALL platform binaries) plus a collapsible file list of what's inside, so
anyone can pull the complete agent for any OS from hub.amd-gaia.ai/hub/<id>.
Pre-built at release time.
- Release: release_agent_email.yml assembles agent-email-<version>.zip (all
platform binaries + npm dist/ + README/SPEC/SKILL/CHANGELOG + binaries.lock.json
+ gaia-agent.yaml + LICENSE) after the lock is regenerated, plus a
package-files.json listing (new gen_package_files.py helper), and publishes both.
- Worker: optional 'package_files' part on /publish -> stored per-version -> the
catalog's package { filename, size_bytes, files } (paired with the .zip
artifact). storage/publish/catalog/types/schema + Worker README + 3 tests.
- Website: a Download .zip button + collapsible file list on the agent page,
hidden gracefully when no package was published.
Worker 63 tests + tsc clean; website 0 errors + 19 tests; helper smoke-tested.
|
Verdict: Request changes — one blocking bug means the feature silently never appears in production, even though every test passes. This PR adds a one-click "Download .zip" (all platform binaries + npm client + docs in a single archive) plus a file list to the hub agent page, assembled and uploaded at release time. The design is clean and the Worker/website/schema/docs are all kept in sync. The blocker: the release pipeline publishes the platform binaries first (which creates the version), then publishes the zip + file list in a second POST to that same version. But the Worker only stores the file-list part on the first publish of a version — so on the real release path the file list is silently dropped, and the "Download .zip" button + file list never render. The tests publish the zip and file list together in a single call against a fresh state, so they pass while the production two-step flow fails. This is exactly the "test from the user's real state, not your primed one" trap from CLAUDE.md. Fix: store the package file list whenever the part is present (not gated on first-publish), and add a test that publishes binaries first, then the zip second, and asserts the package still surfaces. 🔍 Technical details🔴 Critical
Downstream consequence: README/CHANGELOG are correctly gated to first-publish because they're sent on that first call. (If write-once immutability for the listing matters, additionally guard with a 🟡 ImportantTest never exercises the two-publish ordering the workflow actually uses ( All three new tests publish the zip + 🟢 Minor
Strengths
|
The whole-package file listing was stored only inside the !versionExists block, but a real release publishes the per-platform binaries first (creating the version) and the whole-package zip + package_files in a SEPARATE later POST. So package_files arrived when versionExists was already true and was silently dropped — the catalog never got `package`, and the download button + file list never rendered in production. Every existing test did a single isolated POST, so versionExists was false there: green tests, dead feature (a cold-state miss). - Move the package_files write out of the first-POST gate; key it per version and guard with a head() check (the immutable zip artifact 409s before here anyway). - Add a regression test that publishes a binary first, THEN the zip+package_files in a second POST, asserting index.json ends up with `package` populated. It fails on the old code and passes on the fix. - Edge fetch-verify the published zip (200 + Content-Length == local size, same bounded retry as the binaries). The zip rides the artifact path and is SHA- verified on upload, but it is not in binaries.lock.json so the fetch CLI did not cover it — a non-propagated/edge-blocked zip would have shipped a 404 button. worker: 64 tests (+1) pass, tsc clean.
|
Deep pre-release review found one release-blocking bug — now fixed in Blocker: the file listing was never written on a real release — the whole feature was invisible in production. The Worker stored 🔍 Fix + the other items
Verified clean: zip byte integrity (server + local SHA, fail-loud), graceful degradation for agents without a zip ( Merge-order note (with #1846): both PRs add a |
…ail 0.2.4 (amd#1855) Gets the email-agent release unblocked. The ~177 MB all-platforms whole-package zip (amd#1843) exceeds **Cloudflare's edge upload limit** — `POST /publish` returns `413 Payload Too Large` before the request even reaches the worker, which blocked the release on 0.2.1–0.2.3 (each published its binaries but never the zip/npm). That edge limit is plan-based and not fixable in worker code, so the worker-side streaming attempt ([amd#1849](amd#1849)) couldn't have solved it. This reverts that streaming change and disables the whole-package zip publish (`if: false`, with a note to revive it via presigned-to-R2 or per-platform zips). **0.2.4 ships the per-platform binaries + npm client + website with no combined zip** — the binaries stay individually downloadable from the Hub. No agent wire-contract change (`SCHEMA_VERSION` stays 2.0). <details> <summary>What's in here</summary> - **Revert amd#1849** — restores the worker + `publish_to_r2.py` to the multipart-only path; worker suite back to 64 tests passing. - **Disable the zip steps** — "Assemble + publish the whole-package zip" and its edge-verify step are `if: false`; the binary fetch-verify, npm publish, and website redeploy are untouched. - **0.2.4 bump** — all six version targets synced via `stamp_version.py` + CHANGELOG. </details> ## Test plan - [x] `stamp_version.py --check` passes (all targets 0.2.4) - [x] worker `npm run typecheck && npm test` — 64 pass (revert clean) - [x] `cd hub/agents/npm/agent-email && npm run build && npm test` — 46 pass - [ ] Tag `agent-pkg-email-v0.2.4` → release publishes binaries + npm @0.2.4 + website (no zip step) --------- Co-authored-by: Tomasz Iniewicz <tomasz@iniewicz.com>
Why this matters
The hub agent page showed only metadata — a visitor couldn't actually grab the package, and any "download" would have been a single platform binary, not the whole thing. This adds a one-click Download .zip (one archive containing the npm client, all docs, and every platform binary) plus a file list of exactly what's inside — so anyone can pull the complete agent for any OS straight from
hub.amd-gaia.ai/hub/<id>.Design (chosen up front): one cross-platform zip, pre-built at release time (the publish pipeline assembles + uploads it; the hub just links to a stored object).
What's in it
release_agent_email.yml): after the binaries publish and the lock is regenerated with real hashes, assembleagent-email-<version>.zip—binaries/(all platforms) +dist/(npm client) + README/SPEC/SKILL/CHANGELOG +binaries.lock.json+gaia-agent.yaml+ LICENSE — emit apackage-files.jsonlisting (newgen_package_files.py), and POST both (zip artifact +package_files).package_filespart on/publish→ stored per-version → paired with the.zipartifact into the catalog'spackage({ filename, size_bytes, files }).storage/publish/catalog/types/schema + Worker README + 3 tests.Test plan
cd workers/agent-hub && npm test(63 pass) +npx tsc --noEmitcd website && npx astro check(0 errors) +npx vitest run(19) + buildpython hub/agents/python/email/packaging/gen_package_files.py <dir> out.json→ sorted{files:[{name,size_bytes}]}publish_to_r2.py --helpshows--package-files/hub/emailshows the Download .zip button + file list (the zip appears live only once a release publishes it — pre-built at release time)